package com.google.code.yargon.engine;

import java.util.HashMap;

import org.apache.log4j.Logger;

import com.google.code.yargon.Yargon;
import com.google.code.yargon.level.*;
import com.google.code.yargon.ui.RenderEngine;
import com.google.code.yargon.util.LogUtil;

import static com.google.code.yargon.engine.AttributeSet.*;
import static com.google.code.yargon.engine.SkillSet.*;

/**
 * Character class
 * 
 * @author Mika Myllynen
 *
 */
public class Player extends Creature {
	
	// Attributes & skills
	private AttributeSet as = new AttributeSet(); 
	private SkillSet ss = new SkillSet();
	
	// Start by default from 0,0 at first level
	private Location l = new Location(0,0,0);
	
	// Level states (known & visible areas for each level)
	private HashMap<Integer, LevelState> levelStates;
	
	private Logger log = LogUtil.getInstance();
		
	// New character
	public Player() {
		levelStates = new HashMap<Integer, LevelState>();
		
		as.set(ATT_STR, Cast.castValueBetween(3, 18));
		as.set(ATT_DEX, Cast.castValueBetween(3, 18));
		as.set(ATT_INT, Cast.castValueBetween(3, 18));
		as.set(ATT_WIS, Cast.castValueBetween(3, 18));
		as.set(ATT_CHA, Cast.castValueBetween(3, 18));
		as.set(ATT_CUN, Cast.castValueBetween(3, 18));
	}
		
	/**
	 * Get character location
	 * 
	 * @return location
	 */
	public Location getLocation() {
		return l;
	}

	/**
	 * Set character location
	 * 
	 * @param location
	 */
	public void setLocation(Location location) {
		this.l = location;
	}
	
	/**
	 * Get character attributes
	 * 
	 * @return
	 */
	public AttributeSet getAttributeSet() {
		return as;
	}
	
	/**
	 * Get character skills
	 * 
	 * @return
	 */
	public SkillSet getSkillSet() {
		return ss;
	}
	
	/**
	 * Get level state for the current level. Creates level state for current level if it does not exists yet.
	 * 
	 * @return
	 */
	public LevelState getLevelState() {
		if(levelStates.get(l.getZ()) == null) {
			LevelState current = new LevelState(LevelManager.getInstance().get(0));
			levelStates.put(l.getZ(), current);
		}	
		return this.levelStates.get(l.getZ());
	}
	
	/**
	 * Move the character to direction d
	 * @param d
	 * @param level
	 */
	public void moveTo(Direction d, LevelArea level) {	
		if(level.isFloor(l.toDirection(d)) || level.isTunnel(l.toDirection(d))) {
			l.moveTo(d);
			getLevelState().update(l, level);
			setRefresh(true);
		} 
		else if(level.isDoor(l.toDirection(d)) && (((DoorBlock)level.get(l.toDirection(d))).isOpen() || ((DoorBlock)level.get(l.toDirection(d))).getDurability() == 0)) {
			l.moveTo(d);
			getLevelState().update(l, level);
			setRefresh(true);
		}		
		else {
			RenderEngine.getInstance().message("Nggghh!");
		}
	}
	
	/**
	 * Use a door to direction d
	 * 
	 * @param d
	 * @param level
	 */
	public void useDoor(Direction d, LevelArea level) {
		
		// Door at the player location?
		if(d == null) {
			
			// Is really a door
			if(level.isDoor(l)) {
				DoorBlock db = (DoorBlock)level.get(l);
				
				// Cannot close a broken door
				if(db.getDurability() == 0) {
					RenderEngine.getInstance().message("You try to close the door remnants but to no avail");
				}
			
				// Close in your face
				else {
					db.close();
					l.moveTo(db.getDirection());
					RenderEngine.getInstance().message("Wham! You hit yourself with the door");
					getLevelState().update(l, level);
					setRefresh(true);
				}
			}
			
			// Not a door
			else {
				RenderEngine.getInstance().message("You are not standing in a doorway!");
			}
		}
		
		// Door to some direction from player
		else if(level.isDoor(l.toDirection(d))) {		
			DoorBlock db = (DoorBlock)level.get(l.toDirection(d));
			
			// Open - close it
			if(db.isOpen()) {
				
				// Cannot close a broken door
				if(db.getDurability() == 0) {
					RenderEngine.getInstance().message("You try to close the door remnants but to no avail");
				}
				
				else {
					db.close();
					RenderEngine.getInstance().message("Door closed");
					getLevelState().update(l, level);
					setRefresh(true);
				}
			} 
			
			// Closed, open it
			else {
				
				// Cannot open a broken door
				if(db.getDurability() == 0) {
					RenderEngine.getInstance().message("It's broken, just walk through it!");
				}
				
				else {
					db.open();
					RenderEngine.getInstance().message("Door opened");
					getLevelState().update(l, level);
					setRefresh(true);
				}
			}
		} 
		
		// Not a door
		else {
			RenderEngine.getInstance().message("There is no door in that direction!");
		}		
	}
}
